home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / sugg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  8.3 KB  |  475 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: sugg.c,v 2.4 84/10/26 12:10:51 guido Exp $";
  3.  
  4. /*
  5.  * B editor -- New suggestion handling module.
  6.  */
  7.  
  8. #include "feat.h"
  9.  
  10. #ifdef USERSUGG
  11.  
  12. #include "b.h"
  13. #include "bobj.h"
  14. #include "node.h"
  15. #include "supr.h"
  16. #include "gram.h"
  17. #include "queu.h"
  18.  
  19. #include <ctype.h>
  20.  
  21. extern bool dflag;
  22. extern bool edontop;
  23.  
  24. extern bool lefttorite;
  25.  
  26. #ifndef SUGGFILE
  27. #define SUGGFILE ".Bed_sugg"
  28. #endif
  29.  
  30. #define MAXNSUGG 1000
  31.  
  32. Hidden value sugg[MAXNSUGG];
  33. Hidden int nsugg;
  34. Hidden int nbuiltin;
  35. Hidden bool suggchanges;
  36. Hidden bool ignorefirstcall; /* Communication between killsugg and setsugg */
  37.  
  38. /*
  39.  * Read the suggestion table from file.
  40.  */
  41.  
  42. Visible Procedure
  43. initsugg()
  44. {
  45.     char buffer[1000];
  46.     register FILE *fp;
  47.     register c;
  48.  
  49.     fp = fopen(SUGGFILE, "r");
  50.     if (!fp) {
  51.         if (dflag) {
  52.             fprintf(stderr, "*** No suggestion file: ");
  53.             perror(SUGGFILE);
  54.         }
  55.         return;
  56.     }
  57.     while (fgets(buffer, sizeof buffer, fp)) {
  58.         if (!index(buffer, '\n')) { /* Skip long line */
  59.             fprintf(stderr,
  60.                 "*** Excessively long suggestion ignored\n");
  61.             while ((c = getc(fp)) != '\n' && c != EOF)
  62.                 ;
  63.         }
  64.         else
  65.             addsugg(buffer, -1);
  66.     }
  67.     fclose(fp);
  68. }
  69.  
  70.  
  71. /*
  72.  * Make sure a line looks like a suggestion, return No if not.
  73.  * Replace the trailing newline or comment-sign by a zero byte.
  74.  * ***** Should check more thoroughly. *****
  75.  */
  76.  
  77. Hidden bool
  78. checksugg(bp)
  79.     string bp;
  80. {
  81.     if (!isascii(*bp) || !isupper(*bp))
  82.         return No;
  83.     while (*bp && *bp != '\n' && *bp != '\\')
  84.         ++bp;
  85.     *bp = 0;
  86.     return Yes;
  87. }
  88.  
  89.  
  90. /*
  91.  * Procedure to add a suggestion to the suggestion table.
  92.  */
  93.  
  94. Visible Procedure
  95. addsugg(str, builtin)
  96.     string str;
  97.     int builtin;
  98. {
  99.     int i;
  100.     int j;
  101.     int len;
  102.     int cmp;
  103.     string suggi;
  104.     int where = (builtin == -1) ? nsugg : nbuiltin;
  105.  
  106.     if (!checksugg(str))
  107.         return;
  108.     for (len = 0; str[len] && str[len] != ' '; ++len)
  109.         ;
  110.     for (i = nsugg-1; i >= 0; --i) {
  111.         suggi = Str(sugg[i]);
  112.         cmp = strncmp(str, suggi, len);
  113.         if (cmp < 0)
  114.             continue;
  115.         if (cmp > 0) {
  116.             if (i >= where)
  117.                 where = i+1;
  118.             continue;
  119.         }
  120.         if (suggi[len] && suggi[len] != ' ')
  121.             continue; /* No match, just prefix */
  122.         if (Strequ(str+len, suggi+len))
  123.             return; /* Ignore exact duplicates */
  124.         if (i < nbuiltin)
  125.             return; /* Cannot replace built-in */
  126.         /* Replacement */
  127.         sugg[i] = mk_text(str); /* No use to release the old one... */
  128.                     /* ...its refcount is infinite */
  129.         fix(sugg[i]);
  130.         suggchanges = Yes;
  131.         return;
  132.     }
  133.     /* Insertion */
  134.     if (nsugg >= MAXNSUGG)
  135.         return; /* Table overflow */
  136.     if (builtin == Yes)
  137.         ++nbuiltin;
  138.     for (j = nsugg; j > where; --j)
  139.         sugg[j] = sugg[j-1];
  140.     ++nsugg;
  141.     sugg[where] = mk_text(str);
  142.     fix(sugg[where]);
  143.     suggchanges = Yes;
  144. }
  145.  
  146.  
  147. /*
  148.  * Procedure to delete a suggestion from the suggestion table.
  149.  * Must supply the whole string as argument.
  150.  */
  151.  
  152. Hidden Procedure
  153. delsugg(str)
  154.     string str;
  155. {
  156.     int i;
  157.  
  158.     for (i = 0; i < nsugg; ++i) {
  159.         if (Strequ(str, Str(sugg[i]))) {
  160.             --nsugg;
  161.             for (; i < nsugg; ++i)
  162.                 sugg[i] = sugg[i+1];
  163.             suggchanges = Yes;
  164.             return;
  165.         }
  166.     }
  167. }
  168.  
  169.  
  170. /*
  171.  * Return a suitable suggestion which matches str for len characters.
  172.  * If len > 1, and all of str (even beyond len) equals some table
  173.  * entry, the first matching entry after that is preferred; otherwise,
  174.  * the first matching entry at all is returned.
  175.  * Vnil is returned if no entry matches.
  176.  */
  177.  
  178. Hidden node
  179. nextsugg(str, len)
  180.     string str;
  181.     int len;
  182. {
  183.     bool found = !str[len];
  184.     int first = -1;
  185.     int i;
  186.  
  187.     for (i = 0; i < nsugg; ++i) {
  188.         if (!Strnequ(str, Str(sugg[i]), len))
  189.             continue;
  190.         if (found)
  191.             return (node) sugg[i];
  192.         if (Strequ(str+len, Str(sugg[i])+len))
  193.             found = Yes;
  194.         if (first < 0)
  195.             first = i;
  196.     }
  197.     if (first >= 0)
  198.         return (node) sugg[first];
  199.     return Nnil;
  200. }
  201.  
  202.  
  203. /*
  204.  * Procedure to save the suggestion file if it has been changed.
  205.  */
  206.  
  207. Visible Procedure
  208. endsugg()
  209. {
  210.     FILE *fp;
  211.     int i;
  212.  
  213.     if (!suggchanges)
  214.         return;
  215.     suggchanges = No;
  216.     fp = fopen(SUGGFILE, "w");
  217.     if (!fp) {
  218.         if (dflag) {
  219.             fprintf(stderr, "*** Can't rewrite ");
  220.             perror(SUGGFILE);
  221.         }
  222.         return;
  223.     }
  224.     if (dflag)
  225.         fprintf(stderr, "*** [Rewriting suggestion file]\n");
  226.     for (i = nbuiltin; i < nsugg; ++i)
  227.         fprintf(fp, "%s\n", Str(sugg[i]));
  228.     if (fclose(fp) == EOF) {
  229.         fprintf(stderr, "*** Can't finish writing ");
  230.         perror(SUGGFILE);
  231.         return;
  232.     }
  233. }
  234.  
  235.  
  236. /*
  237.  * Find a new suggestion or advance in the current one.
  238.  * Interface styled like resuggest: string pointer is advanced here.
  239.  */
  240.  
  241. Visible bool
  242. newsugg(ep, pstr, alt_c)
  243.     environ *ep;
  244.     string *pstr;
  245.     int alt_c;
  246. {
  247.     char buffer[1000];
  248.     node n = tree(ep->focus);
  249.     node nn;
  250.     int sym = symbol(n);
  251.     string str;
  252.     string bp;
  253.     bool end;
  254.  
  255.     Assert(pstr && *pstr);
  256.     if (sym != Suggestion || ep->mode != VHOLE || ep->s1 != 2)
  257.         return No;
  258.     strncpy(buffer, Str((value)firstchild(n)), sizeof buffer);
  259.     for (str = *pstr, bp = buffer+ep->s2, end = No;
  260.             *str && bp < buffer + sizeof buffer; ++str, ++bp) {
  261.         if (!*bp)
  262.             end = Yes;
  263.         *bp = *str;
  264.     }
  265.     if (end)
  266.         *bp = 0;
  267.     nn = (node)nextsugg(buffer, ep->s2 + 1);
  268.     if (!nn) {
  269.         if (!alt_c)
  270.             return No;
  271.         buffer[ep->s2] = alt_c;
  272.         nn = (node)nextsugg(buffer, ep->s2 + 1);
  273.         if (!nn)
  274.             return No;
  275.     }
  276.     if (nn != firstchild(n)) {
  277.         s_down(ep);
  278.         replace(&ep->focus, nn);
  279.         s_up(ep);
  280.     }
  281.     /* No need to release because its refcount is infinite anyway */
  282.     ++ep->s2;
  283.     if (**pstr == ' ')
  284.         accsugg(ep);
  285.     ++*pstr;
  286.     return Yes;
  287. }
  288.  
  289.  
  290. /*
  291.  * Kill suggestion -- only the part to the left of the focus is kept.
  292.  */
  293.  
  294. Visible Procedure
  295. killsugg(ep)
  296.     environ *ep;
  297. {
  298.     queue q = Qnil;
  299.     char buffer[1000];
  300.     node n = tree(ep->focus);
  301.  
  302.     Assert(ep->mode == VHOLE && ep->s1 == 2 && symbol(n) == Suggestion);
  303.     strncpy(buffer, Str((value)firstchild(n)), ep->s2);
  304.     buffer[ep->s2] = 0;
  305.     delfocus(&ep->focus);
  306.     ep->mode = WHOLE;
  307.     ignorefirstcall = Yes;
  308.     ins_string(ep, buffer, &q, 0);
  309.     qrelease(q);
  310.     ignorefirstcall = No;
  311. }
  312.  
  313.  
  314. /*
  315.  * Place an initial suggestion in a node.
  316.  */
  317.  
  318. Visible bool
  319. setsugg(pp, c, ep)
  320.     path *pp;
  321.     char c;
  322.     environ *ep;
  323. {
  324.     char buf[2];
  325.     node n;
  326.  
  327.     if (lefttorite)
  328.         return No;
  329.     if (ignorefirstcall) {
  330.         ignorefirstcall = No;
  331.         return No;
  332.     }
  333.     buf[0] = c;
  334.     buf[1] = 0;
  335.     n = (node)nextsugg(buf, 1);
  336.     if (!n)
  337.         return No;
  338.     replace(pp, newnode(1, Suggestion, &n));
  339.     ep->mode = VHOLE;
  340.     ep->s1 = 2;
  341.     ep->s2 = 1;
  342.     return Yes;
  343. }
  344.  
  345.  
  346. /*
  347.  * Accept a suggestion -- turn it into real nodes.
  348.  */
  349.  
  350. Visible Procedure
  351. accsugg(ep)
  352.     environ *ep;
  353. {
  354.     node n = tree(ep->focus);
  355.     int s2 = ep->s2;
  356.     queue q = Qnil;
  357.     environ env;
  358.  
  359.     Assert(symbol(n) == Suggestion && ep->mode == VHOLE && ep->s1 == 2);
  360.     stringtoqueue(Str((value)firstchild(n)) + s2, &q);
  361.     killsugg(ep);
  362.     Ecopy(*ep, env);
  363.     if (app_queue(ep, &q))
  364.         Erelease(env);
  365.     else {
  366.         Erelease(*ep);
  367.         Emove(env, *ep);
  368.         qrelease(q);
  369.     }
  370. }
  371.  
  372.  
  373. /*
  374.  * Procedure called when a unit is read in.
  375.  * It tries to update the suggestion database.
  376.  * It also remembers the suggestion so that it can be removed by writesugg
  377.  * if that finds the unit was deleted.
  378.  */
  379.  
  380. Hidden char lastsugg[1000];
  381.  
  382. Visible Procedure
  383. readsugg(p)
  384.     path p;
  385. {
  386.     p = pathcopy(p);
  387.     top(&p);
  388.     getpattern(lastsugg, tree(p));
  389.     pathrelease(p);
  390.     addsugg(lastsugg, No);
  391. }
  392.  
  393.  
  394. /*
  395.  * Procedure called when a unit is saved.
  396.  * It tries to update the suggestion database.
  397.  * If the unit appears empty, the last suggestion passed to readsugg
  398.  * will be deleted.
  399.  */
  400.  
  401. Visible Procedure
  402. writesugg(p)
  403.     path p;
  404. {
  405.     p = pathcopy(p);
  406.     top(&p);
  407.     if (width(tree(p)) == 0)
  408.         delsugg(lastsugg);
  409.     else {
  410.         getpattern(lastsugg, tree(p));
  411.         if (lastsugg[0])
  412.             addsugg(lastsugg, No);
  413.     }
  414.     pathrelease(p);
  415. }
  416.  
  417.  
  418. /*
  419.  * Procedure to find out the suggestion that fits the current unit.
  420.  * Makes the buffer empty if not a HOW'TO unit.
  421.  * ***** Won't work if B-grammar is severely changed! *****
  422.  */
  423.  
  424. Hidden Procedure
  425. getpattern(buffer, n)
  426.     string buffer;
  427.     node n;
  428. {
  429.     string *rp = noderepr(n);
  430.  
  431.     buffer[0] = 0;
  432.     while (Fw_zero(rp[0])) {
  433.         if (nchildren(n) == 0)
  434.             return;
  435.         n = firstchild(n);
  436.         rp = noderepr(n);
  437.     }
  438.     if (!Strequ(rp[0], "HOW'TO ") || nchildren(n) < 1)
  439.         return;
  440.     subgetpattern(&buffer, firstchild(n));
  441.     *buffer = 0;
  442. }
  443.  
  444.  
  445. /*
  446.  * Refinement for getpattern to do the work.
  447.  */
  448.  
  449. Hidden Procedure
  450. subgetpattern(pbuf, n)
  451.     string *pbuf;
  452.     node n;
  453. {
  454.     string *rp;
  455.     int i;
  456.     int nch;
  457.  
  458.     rp = noderepr(n);
  459.     nch = (Type(n) == Tex) ? 0 : nchildren(n);
  460.     for (i = 0; i <= nch; ++i) {
  461.         if (i > 0)
  462.             subgetpattern(pbuf, child(n, i));
  463.         if (Fw_positive(rp[i])) {
  464.             if (islower(rp[i][0]))
  465.                 *(*pbuf)++ = '?';
  466.             else {
  467.                 strcpy(*pbuf, rp[i]);
  468.                 *pbuf += strlen(*pbuf);
  469.             }
  470.         }
  471.     }
  472. }
  473.  
  474. #endif USERSUGG
  475.